package com.example.jpademo.ref.generate.impl;


import com.example.jpademo.ref.generate.IRefGenerateService;
import com.example.jpademo.ref.generate.enums.CommonDelReferSQL;
import com.example.jpademo.ref.generate.enums.CommonIdIncrSQL;
import com.example.jpademo.ref.generate.enums.CommonInsertSQL;
import com.example.jpademo.ref.generate.vo.RefItemEntityBase;
import com.example.jpademo.ref.generate.vo.ReferDataDTO;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
@ConditionalOnProperty(
        prefix = "devtool",
        value = {"refgenerate"},
        havingValue = "true",
        matchIfMissing = false
)
public class RefGenerateServiceImpl implements IRefGenerateService {
    private JdbcTemplate jdbcTemplate;

    public RefGenerateServiceImpl() {
        jdbcTemplate = new JdbcTemplate(dataSource(),true);
    }

    @Override
    public String createRerDataSql(ReferDataDTO referDataDTO) {
        return this.createRefData(referDataDTO,false);

    }
    @Override
    public void createRefData(ReferDataDTO referDataDTO) {
        this.createRefData(referDataDTO, true);
    }


    private String createRefData(ReferDataDTO referDataDTO,boolean execute) {
        Objects.requireNonNull(referDataDTO,"referDataDTO对象不能为空");
        Objects.requireNonNull(referDataDTO.getRefCode(),"参照编码对象不能为空");
        Objects.requireNonNull(referDataDTO.getRefName(),"参照名称对象不能为空");
        //Objects.requireNonNull(,"referDataDTO对象不能为空");
        Objects.requireNonNull(referDataDTO.getDsSql(),"sql语句不能为空");
        Objects.requireNonNull(referDataDTO.getTplType(),"参照UI类型对象不能为空");
        Objects.requireNonNull(referDataDTO.getMetaName(),"参照的元数据uri对象不能为空");
        //Objects.requireNonNull(referDataDTO.getRefDomain(),"租户domain对象不能为空");
        Objects.requireNonNull(referDataDTO.getTenantId(),"租户id对象不能为空");
        if(!CollectionUtils.isEmpty(referDataDTO.getEntityBaseList())){
            boolean flag = referDataDTO.getEntityBaseList().stream().anyMatch(refItemEntityBase -> refItemEntityBase.getColumn().toLowerCase().equals("id"));
            if(!flag){
                throw new RuntimeException("参照字段未存在id,请重新配置");
            }
        }else{
            throw new RuntimeException("参照字段不能为null");
        }

        String dsType = StringUtils.isEmpty(referDataDTO.getDsType())?"sql":referDataDTO.getDsType();

        return this.createRefData(referDataDTO.getRefCode(),referDataDTO.getRefName(),dsType,referDataDTO.getDsSql(),referDataDTO.getTplType(),
                referDataDTO.getMetaName(),referDataDTO.getRefDomain(),referDataDTO.getTenantId(),referDataDTO.getEntityBaseList(),execute);
    }

    public String createRefData(String refCode, String refName, String dsType, String dsSql, String tplType, String metaName, String refDomain, String tenantId, List<RefItemEntityBase> entityBaseList,boolean execute) {
        StringBuffer sqlBuffer = new StringBuffer(deleteRefData(refCode,tenantId,execute)).append(";\n");
        sqlBuffer.append("\n").append(incrIds(execute)).append(";\n");
        sqlBuffer.append("\n").append(insertRefData(refCode,refName,dsType,dsSql,tplType,metaName,refDomain,tenantId,entityBaseList,execute)).append(";\n");
        //sql.append("\n").append( updateRefData(execute));
        return sqlBuffer.toString();
    }

    /**
     * 删除参照数据
     * @param refCode
     * @param tenantId
     */
    private String deleteRefData(String refCode,String tenantId,boolean execute){
        String[] batchDelSql = new String[6];
        batchDelSql[0] = String.format(CommonDelReferSQL.DELETE_BILLENTITY_BASE.getSql(),refCode,tenantId);
        batchDelSql[1] = String.format(CommonDelReferSQL.DELETE_BILLTEMPLATE_BASE.getSql(),refCode,tenantId);
        batchDelSql[2] = String.format(CommonDelReferSQL.DELETE_BILLTMP_BASE.getSql(),refCode,tenantId);
        batchDelSql[3] = String.format(CommonDelReferSQL.DELETE_BILLITEM_BASE.getSql(),refCode,tenantId);
        batchDelSql[4] = String.format(CommonDelReferSQL.DELETE_BILL_BASE.getSql(),refCode,tenantId);
        batchDelSql[5] = String.format(CommonDelReferSQL.DELETE_PUB_REF.getSql(),refCode);
        Arrays.stream(batchDelSql).forEach(System.out::println);
        if(execute) {
            jdbcTemplate.batchUpdate(batchDelSql);
        }
        return Arrays.stream(batchDelSql).collect(Collectors.joining(";\n"));
    }

    /**
     * 插入参照数据
     * @param refCode
     * @param refName
     * @param dsType
     * @param dsSql
     * @param tplType
     * @param refDomain
     * @param tenantId
     * @param entityBaseList
     */
    private String insertRefData(String refCode, String refName,String dsType, String dsSql,String tplType,String metaName,String refDomain,String tenantId, List<RefItemEntityBase> entityBaseList,boolean execute){
        if(StringUtils.isEmpty(dsSql)){
            dsSql = "select " + entityBaseList.stream().map(RefItemEntityBase::getColumn).collect(Collectors.joining(",")) + " from " + refDomain + " where dr=0";
        }


        String[] batchInsertSql = new String[5 + entityBaseList.size()];
        batchInsertSql[0] = String.format(CommonInsertSQL.BILL_BASE_INSERT.getSql(),refCode,refName,tenantId);
        batchInsertSql[1] = String.format(CommonInsertSQL.BILLENTITY_BASE_INSERT.getSql(),refCode,refName,metaName,tenantId);
        batchInsertSql[2] = String.format(CommonInsertSQL.BILLTEMPLATE_BASE_INSERT.getSql(),refCode,refName,tenantId);
        batchInsertSql[3] = String.format(CommonInsertSQL.BILLTPL_BASE_INSERT.getSql(),metaName,tenantId);
        batchInsertSql[4] = String.format(CommonInsertSQL.PUB_REF_INSERT.getSql(),refCode,refName,refName,refCode,dsType,dsSql,tplType,refCode,refDomain);

        IntStream.range(0,entityBaseList.size()).forEach(i -> {
            RefItemEntityBase itemEntityBase = entityBaseList.get(i);
            batchInsertSql[5+i] = String.format(CommonInsertSQL.BILLITEM_BASE_INSERT.getSql(),
                    i,
                    itemEntityBase.getColumn(),itemEntityBase.getColumn(),
                    itemEntityBase.getName(),itemEntityBase.getName(),
                    itemEntityBase.getNum(),
                    itemEntityBase.getShow()^1,
                    itemEntityBase.getWidth(),
                    itemEntityBase.getShow(),
                    metaName,
                    itemEntityBase.getOrderby(),
                    tenantId);
        });
        Arrays.stream(batchInsertSql).forEach(System.out::println);
        if(execute){
            jdbcTemplate.batchUpdate(batchInsertSql);
        }
        return Arrays.stream(batchInsertSql).collect(Collectors.joining(";\n"));
    }

    /**
     * 主键自增
     */
    private String incrIds(boolean execute) {
        Arrays.asList(CommonIdIncrSQL.BILL_BASE_ID.getSql(),
                CommonIdIncrSQL.BILLENTITY_BASE_ID.getSql(),
                CommonIdIncrSQL.BILLTEMPLATE_BASE_ID.getSql(),
                CommonIdIncrSQL.BILTPL_BASE_ID.getSql(),
                CommonIdIncrSQL.BILLITEM_BASE_ID.getSql(),
                CommonIdIncrSQL.PUB_REF_ID.getSql()
        ).forEach(System.out::println);
        if (execute) {
            Arrays.asList(CommonIdIncrSQL.BILL_BASE_ID.getSql(),
                    CommonIdIncrSQL.BILLENTITY_BASE_ID.getSql(),
                    CommonIdIncrSQL.BILLTEMPLATE_BASE_ID.getSql(),
                    CommonIdIncrSQL.BILTPL_BASE_ID.getSql(),
                    CommonIdIncrSQL.BILLITEM_BASE_ID.getSql(),
                    CommonIdIncrSQL.PUB_REF_ID.getSql()).forEach(sql -> jdbcTemplate.execute(sql));
        }
        return String.join(";\n", Arrays.asList(CommonIdIncrSQL.BILL_BASE_ID.getSql(),
                CommonIdIncrSQL.BILLENTITY_BASE_ID.getSql(),
                CommonIdIncrSQL.BILLTEMPLATE_BASE_ID.getSql(),
                CommonIdIncrSQL.BILTPL_BASE_ID.getSql(),
                CommonIdIncrSQL.BILLITEM_BASE_ID.getSql(),
                CommonIdIncrSQL.PUB_REF_ID.getSql()));
    }


    /**
     * 更新数据,暂不需要;
     */
    private String updateRefData(boolean execute){
        return "";
    }

    public void testSelectInto(){
        String sql = "select ifnull(max(id),0)+1 into @id26 from pub_ref";
        jdbcTemplate.execute(sql);
    }

    private DataSource dataSource(){
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("application.properties");
        Properties props = new Properties();
        try {
            props.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return DataSourceBuilder.create()
                .driverClassName(props.getProperty("auth.db.driver-class-name"))
                .url(props.getProperty("auth.db.jdbc-url"))
                .username(props.getProperty("auth.db.username"))
                .password(props.getProperty("auth.db.password"))
                .type(HikariDataSource.class)
                .build();
    }

}
